"""
定时任务模块
用于定期更新优书单（龙空书单）和书籍信息
"""
import asyncio
import random
from datetime import datetime
from novelapp.common.common import setLog
from novelapp.api.lkbooklist import (
    fetch_lk_booklists_from_api,
    save_booklists_to_db,
    fetch_booklist_books_from_api,
    save_booklist_books_to_db
)
from novelapp.models.models import LkBookList
from mongoengine.queryset.visitor import Q

# 设置日志
logger = setLog('scheduler_tasks.log')


async def sync_youshudan_lists(
    max_pages: int = 50,
    sort_order: str = "DEFAULT",
    category: str = None
):
    """
    增量同步优书单列表和书籍（按最新活跃时间排序）
    
    逻辑:
    1. 按 DEFAULT(最新活跃) 排序获取书单
    2. 逐个检查书单是否已存在且书籍数相同
    3. 如果发现已存在且数量相同,停止同步(后面的都是旧数据)
    4. 对于新书单或书籍数变化的书单,入库书单信息并同步其所有书籍
    
    Args:
        max_pages: 最多同步页数，默认50页
        sort_order: 排序方式，默认DEFAULT（按最新活跃时间）
        category: 分类筛选（male/female），默认不筛选
        
    Returns:
        dict: 同步结果统计
    """
    logger.info(f"========== 开始增量同步优书单列表和书籍 ==========")
    logger.info(f"参数: max_pages={max_pages}, sort_order={sort_order}, category={category}")
    
    start_time = datetime.now()
    total_lists_saved = 0
    total_books_saved = 0
    page = 1
    page_size = 20
    should_stop = False  # 是否应该停止同步
    
    try:
        while page <= max_pages and not should_stop:
            logger.info(f"正在同步第 {page}/{max_pages} 页...")
            
            # 随机延迟，防止被封
            await asyncio.sleep(random.uniform(1, 2))
            
            # 获取书单列表
            book_lists_data, has_more, total = await fetch_lk_booklists_from_api(
                page=page,
                page_size=page_size,
                sort_order=sort_order,
                category=category
            )
            
            if not book_lists_data:
                logger.info(f"第 {page} 页没有数据，结束同步")
                break
            
            # 逐个处理书单
            for idx, book_list_item in enumerate(book_lists_data):
                list_id = book_list_item.get('listId')
                api_book_count = book_list_item.get('bookCount', 0)
                list_title = book_list_item.get('title', '')
                
                if not list_id:
                    continue
                
                # 检查数据库中是否已存在该书单
                existing = LkBookList.objects(listId=list_id).first()
                
                if existing:
                    db_book_count = existing.bookCount or 0
                    
                    if db_book_count == api_book_count:
                        # 已存在且书籍数相同,停止整个同步
                        logger.info(f"发现已同步书单: {list_id} - {list_title} (书籍数: {api_book_count})")
                        logger.info(f"书籍数量相同,停止同步 (已是最新数据)")
                        should_stop = True
                        break
                    else:
                        # 书籍数量有变化,需要更新
                        logger.info(f"书单 {list_id} 书籍数变化: {db_book_count} -> {api_book_count}, 需要更新")
                else:
                    # 新书单
                    logger.info(f"发现新书单: {list_id} - {list_title} (书籍数: {api_book_count})")
                
                # 保存/更新书单到数据库
                saved_count = save_booklists_to_db([book_list_item])
                if saved_count > 0:
                    total_lists_saved += 1
                    logger.info(f"  书单已入库: {list_id}")
                
                # 同步该书单的所有书籍
                logger.info(f"  开始同步书单 {list_id} 的书籍...")
                books_saved = await sync_booklist_books(list_id, api_book_count)
                total_books_saved += books_saved
                logger.info(f"  书单 {list_id} 书籍同步完成: 入库 {books_saved} 本")
                
                # 更新书单的同步时间
                book_list_obj = LkBookList.objects(listId=list_id).first()
                if book_list_obj:
                    book_list_obj.booksLastSyncAt = datetime.now()
                    book_list_obj.lastUpdated = datetime.now()
                    book_list_obj.save()
            
            if should_stop:
                logger.info(f"在第 {page} 页停止同步")
                break
            
            # 检查是否继续
            if not has_more:
                logger.info("已无更多数据 (hasMore=false)")
                break
            
            page += 1
        
        end_time = datetime.now()
        duration = (end_time - start_time).total_seconds()
        
        result = {
            "success": True,
            "total_pages": page,
            "total_lists_saved": total_lists_saved,
            "total_books_saved": total_books_saved,
            "stopped_early": should_stop,
            "duration_seconds": duration,
            "start_time": start_time.strftime('%Y-%m-%d %H:%M:%S'),
            "end_time": end_time.strftime('%Y-%m-%d %H:%M:%S')
        }
        
        logger.info(f"========== 优书单增量同步完成 ==========")
        logger.info(f"总页数: {page}, 书单入库: {total_lists_saved}, 书籍入库: {total_books_saved}, 耗时: {duration:.2f}秒")
        
        return result
        
    except Exception as e:
        logger.error(f"同步优书单列表失败: {str(e)}")
        return {
            "success": False,
            "error": str(e),
            "total_lists_saved": total_lists_saved,
            "total_books_saved": total_books_saved
        }


async def sync_booklist_books(list_id: str, expected_book_count: int):
    """
    同步单个书单的所有书籍
    
    Args:
        list_id: 书单ID
        expected_book_count: 预期的书籍数量
        
    Returns:
        int: 成功入库的书籍数量
    """
    total_books_saved = 0
    page = 1
    page_size = 20
    fetched_count = 0
    
    try:
        # 获取第一页
        books_data, api_book_count, booklist_info = await fetch_booklist_books_from_api(list_id, 1)
        
        if not books_data and not api_book_count:
            logger.warning(f"    书单 {list_id} 无法获取数据")
            return 0
        
        # 使用API返回的准确数量
        if api_book_count:
            expected_book_count = api_book_count
        
        # 保存第一页数据
        if books_data:
            saved_count = save_booklist_books_to_db(list_id, books_data)
            total_books_saved += saved_count
            fetched_count += len(books_data)
            logger.info(f"    第 {page} 页: 入库 {saved_count} 本 ({fetched_count}/{expected_book_count})")
        
        # 继续获取后续页
        while fetched_count < expected_book_count:
            page += 1
            
            # 随机延迟
            await asyncio.sleep(random.uniform(1, 2))
            
            books_data, _, _ = await fetch_booklist_books_from_api(list_id, page)
            
            if not books_data:
                logger.info(f"    第 {page} 页无数据，结束")
                break
            
            # 入库
            saved_count = save_booklist_books_to_db(list_id, books_data)
            total_books_saved += saved_count
            fetched_count += len(books_data)
            logger.info(f"    第 {page} 页: 入库 {saved_count} 本 ({fetched_count}/{expected_book_count})")
            
            # 如果本页数据不足，说明已是最后一页
            if len(books_data) < page_size:
                break
            
            # 防止无限循环
            if page >= 100:
                logger.warning(f"    已达最大页数100，停止")
                break
        
        return total_books_saved
        
    except Exception as e:
        logger.error(f"    同步书单 {list_id} 书籍失败: {str(e)}")
        return total_books_saved


async def sync_youshudan_books_by_ranges(
    book_count_ranges: list = None,
    max_lists_per_range: int = 30
):
    """
    同步优书单中的书籍信息
    
    Args:
        book_count_ranges: 书籍数量分档，例如 [(100, 20000), (50, 100), (20, 50), (0, 20)]
        max_lists_per_range: 每个分档最多处理的书单数，默认30
        
    Returns:
        dict: 同步结果统计
    """
    logger.info(f"========== 开始同步优书单书籍信息 ==========")
    
    # 默认分档
    if not book_count_ranges:
        book_count_ranges = [
            (100, 20000),  # 100-20000本
            (50, 100),     # 50-100本
            (20, 50),      # 20-50本
            (0, 20)        # 0-20本
        ]
    
    logger.info(f"书籍数量分档: {book_count_ranges}")
    logger.info(f"每档最多处理: {max_lists_per_range} 个书单")
    
    start_time = datetime.now()
    total_lists_processed = 0
    total_books_saved = 0
    range_results = []
    
    try:
        # 逐个分档处理
        for min_books, max_books in book_count_ranges:
            logger.info(f"\n---------- 处理分档: {min_books}-{max_books} ----------")
            
            # 从数据库查询符合条件且需要更新的书单
            query = Q(bookCount__gte=min_books) & Q(bookCount__lte=max_books)
            
            # 优先处理从未同步或3天以上未更新的书单
            book_lists = LkBookList.objects(query).order_by('-bookCount').limit(max_lists_per_range)
            
            range_list_count = book_lists.count()
            logger.info(f"找到 {range_list_count} 个符合条件的书单")
            
            range_books_saved = 0
            range_lists_processed = 0
            
            # 逐个书单处理
            for book_list in book_lists:
                list_id = book_list.listId
                list_title = book_list.title
                book_count = book_list.bookCount
                
                # 检查是否需要更新（超过3天或从未同步）
                now = datetime.now()
                needs_update = False
                
                if not book_list.booksLastSyncAt:
                    needs_update = True
                    logger.info(f"\n处理书单: {list_id} - {list_title} ({book_count}本) [从未同步]")
                else:
                    days_since_sync = (now - book_list.booksLastSyncAt).days
                    if days_since_sync >= 3:
                        needs_update = True
                        logger.info(f"\n处理书单: {list_id} - {list_title} ({book_count}本) [已{days_since_sync}天未更新]")
                    else:
                        logger.info(f"跳过书单: {list_id} - {list_title} (最近已更新)")
                        continue
                
                if not needs_update:
                    continue
                
                # 获取该书单的所有书籍（自动分页）
                page = 1
                list_books_saved = 0
                fetched_count = 0
                page_size = 20
                
                # 获取第一页
                books_data, total_book_count, booklist_info = await fetch_booklist_books_from_api(list_id, 1)
                
                if not books_data and not total_book_count:
                    logger.warning(f"  书单 {list_id} 无法获取数据")
                    continue
                
                # 更新书单信息
                if booklist_info:
                    book_list.bookCount = booklist_info.get('bookCount', book_list.bookCount)
                    book_list.viewCount = booklist_info.get('viewCount', book_list.viewCount)
                    book_list.favoritedCount = booklist_info.get('favoritedCount', book_list.favoritedCount)
                
                # 保存第一页数据
                if books_data:
                    saved_count = save_booklist_books_to_db(list_id, books_data)
                    list_books_saved += saved_count
                    fetched_count += len(books_data)
                    logger.info(f"  第 {page} 页: 入库 {saved_count} 本 ({fetched_count}/{total_book_count})")
                
                # 继续获取后续页
                while fetched_count < total_book_count:
                    page += 1
                    
                    # 随机延迟
                    await asyncio.sleep(random.uniform(1, 2))
                    
                    books_data, _, _ = await fetch_booklist_books_from_api(list_id, page)
                    
                    if not books_data:
                        logger.info(f"  第 {page} 页无数据，结束")
                        break
                    
                    # 入库
                    saved_count = save_booklist_books_to_db(list_id, books_data)
                    list_books_saved += saved_count
                    fetched_count += len(books_data)
                    logger.info(f"  第 {page} 页: 入库 {saved_count} 本 ({fetched_count}/{total_book_count})")
                    
                    # 如果本页数据不足，说明已是最后一页
                    if len(books_data) < page_size:
                        break
                    
                    # 防止无限循环
                    if page >= 100:
                        logger.warning(f"  已达最大页数100，停止")
                        break
                
                # 更新同步时间
                book_list.booksLastSyncAt = now
                book_list.lastUpdated = now
                book_list.save()
                
                range_books_saved += list_books_saved
                range_lists_processed += 1
                logger.info(f"  书单 {list_id} 完成: 共入库 {list_books_saved} 本书")
            
            # 记录本分档结果
            range_results.append({
                "range": f"{min_books}-{max_books}",
                "lists_in_db": range_list_count,
                "lists_processed": range_lists_processed,
                "books_saved": range_books_saved
            })
            
            total_lists_processed += range_lists_processed
            total_books_saved += range_books_saved
            
            logger.info(f"分档 [{min_books}-{max_books}] 完成: 处理 {range_lists_processed} 个书单, 入库 {range_books_saved} 本书")
        
        end_time = datetime.now()
        duration = (end_time - start_time).total_seconds()
        
        result = {
            "success": True,
            "total_lists_processed": total_lists_processed,
            "total_books_saved": total_books_saved,
            "range_results": range_results,
            "duration_seconds": duration,
            "start_time": start_time.strftime('%Y-%m-%d %H:%M:%S'),
            "end_time": end_time.strftime('%Y-%m-%d %H:%M:%S')
        }
        
        logger.info(f"========== 优书单书籍同步完成 ==========")
        logger.info(f"总处理书单: {total_lists_processed}, 总入库书籍: {total_books_saved}, 耗时: {duration:.2f}秒")
        
        return result
        
    except Exception as e:
        logger.error(f"同步优书单书籍失败: {str(e)}")
        return {
            "success": False,
            "error": str(e),
            "total_lists_processed": total_lists_processed,
            "total_books_saved": total_books_saved
        }


async def daily_sync_youshudan():
    """
    每日定时任务：增量同步优书单列表和书籍信息
    
    逻辑:
    1. 按最新活跃时间排序获取书单
    2. 遇到已存在且书籍数相同的书单就停止
    3. 对新书单或有变化的书单,同时入库书单信息和所有书籍
    """
    logger.info(f"\n{'='*60}")
    logger.info(f"开始执行每日优书单增量同步任务")
    logger.info(f"时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    logger.info(f"{'='*60}\n")
    
    # 增量同步书单列表和书籍（同时进行）
    result = await sync_youshudan_lists(max_pages=50)
    
    logger.info(f"\n{'='*60}")
    logger.info(f"每日优书单增量同步任务完成")
    logger.info(f"同步状态: {'成功' if result.get('success') else '失败'}")
    logger.info(f"书单入库: {result.get('total_lists_saved', 0)} 个")
    logger.info(f"书籍入库: {result.get('total_books_saved', 0)} 本")
    logger.info(f"是否提前停止: {'是' if result.get('stopped_early') else '否'}")
    logger.info(f"耗时: {result.get('duration_seconds', 0):.2f} 秒")
    logger.info(f"{'='*60}\n")
    
    return result
